﻿using System.Linq;
using KTOP.Core.Domain.Matrix;

namespace KTOP.Homeworks.Hw5.Logics.CrossMatrix
{
    class GshBuilder
    {
        private Gsh BuildGsh(RMatrix rMatrix)
        {
            var context = new Gsh(rMatrix);

            //calculating G' size
            var gshSize = 0;
            for (var i = 0; i < context.RMatrix.Size; i++)
            {
                for (int j = i + 2; j < context.RMatrix.Size; j++)
                {
                    if (i == 0 && j == context.RMatrix.Size - 1) continue;
                    if (context.RMatrix[i, j] > 0)
                    {
                        context.GshMap.Add(new Link(i, j), gshSize++);
                    }
                }
            }

            context.CreateGshMatrix(gshSize);

            //calculating G'
            int pi = 0;
            for (int i = 1; i < context.RMatrix.Size; i++)
            {
                for (int j = i + 2; j < context.RMatrix.Size; j++)
                {
                    if (context.RMatrix[i, j] > 0)
                    {
                        //looking magic "Eight"
                        for (int q = 0; q < i; q++)
                        {
                            for (int k = i + 1; k < j; k++)
                            {
                                if (context.RMatrix[q, k] > 0)
                                {
                                    context.GshMatrix[context.GshMap[(new Link(q, k))]][
                                        context.GshMap[(new Link(i, j))]] = 1;
                                    context.GshMatrix[context.GshMap[(new Link(i, j))]][
                                        context.GshMap[(new Link(q, k))]] = 1;
                                    pi++;
                                }
                            }
                        }
                    }
                }
            }

            for (int i = 0; i < context.GshMatrix.Count; i++)
            {
                bool isEmptyFound = true;
                for (int j = 0; j < context.GshMatrix.Count; j++)
                {
                    if (context.GshMatrix[i][j] != 0)
                    {
                        isEmptyFound = false;
                    }
                }
                if (isEmptyFound)
                {
                    RemoveRowAndCol(context, i);
                    i--;
                }
            }

            for (int i = 0; i < context.GshMatrix.Count; i++)
            {
                for (int j = 0; j < context.GshMatrix.Count; j++)
                {
                    if (i == j)
                    {
                        context.GshMatrix[i][j] = 1;
                    }
                }
            }

            context.Pi = pi;
            return context;
        }

        private int CreateGshMatrix(Gsh context)
        {
            var pi = 0;
            for (var i = 1; i < context.RMatrix.Size; i++)
                for (var j = i + 2; j < context.RMatrix.Size; j++)
                    if (context.RMatrix[i, j] > 0)
                    {
                        //looking magic "Eight"
                        for (var q = 0; q < i; q++)
                            for (var k = i + 1; k < j; k++)
                                if (context.RMatrix[q, k] > 0)
                                {
                                    var qkPair = new Link(q, k);
                                    var ijPair = new Link(i, j);

                                    context.GshMatrix[context.GshMap[qkPair]][context.GshMap[ijPair]] = 1;
                                    context.GshMatrix[context.GshMap[ijPair]][context.GshMap[qkPair]] = 1;

                                    pi++;
                                }

                    }

            return pi;
        }

        private void FillGshMatrixDiagonal(Gsh context)
        {
            for (var i = 0; i < context.GshMatrix.Count; i++)
                for (var j = 0; j < context.GshMatrix.Count; j++)
                    if (i == j) context.GshMatrix[i][j] = 1;

        }

        private void RemoveEmpty(Gsh context)
        {
            // seems to be not efficient and stupid
            // but this is literal port

            for (var i = 0; i < context.GshMatrix.Count; i++)
            {
                var isEmptyFound = true;
                for (var j = 0; j < context.GshMatrix.Count; j++)
                {
                    if (context.GshMatrix[i][j] != 0)
                    {
                        isEmptyFound = false;
                    }
                }

                if (isEmptyFound)
                {
                    RemoveRowAndCol(context, i);
                    i--;
                }
            }
        }

        public void RemoveRowAndCol(Gsh context, int n)
        {
            var dst = context.GshMatrix.Skip(1).Select(row => row.Skip(1).ToList()).ToList();

            //перезаполняем левый верхний угол
            for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                    dst[i][j] = context.GshMatrix[i][j];

            context.GshMatrix = dst;

            context.GshMap = context.GshMap.Where(kv => kv.Value != n)
                .ToDictionary(kv => kv.Key, kv => kv.Value > n ? kv.Value - 1 : kv.Value);
        }

        private static int CreateGshMap(Gsh context)
        {
            var gshSize = 0;
            for (var row = 0; row < context.RMatrix.Size; row++)
                for (var col = row + 2; col < context.RMatrix.Size; col++)
                {
                    if (row == 0 && col == context.RMatrix.Size - 1) continue;
                 
                    if (context.RMatrix[row, col] > 0)
                        context.GshMap.Add(new Link(row, col), gshSize++);
                }

            return gshSize;
        }

        public static Gsh Buind(RMatrix rMatrix)
        {
            return new GshBuilder().BuildGsh(rMatrix);
        }
    }
}
